import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.*;
import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

public class LineNumberPanel extends JPanel {
    private final JTextComponent textComponent;
    private final JScrollPane scrollPane;
    
    // 用于延迟重绘的定时器
    private Timer repaintTimer;
    
    public LineNumberPanel(JTextComponent textComponent) {
        this.textComponent = textComponent;
        this.scrollPane = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, textComponent);
        
        setPreferredSize(new Dimension(60, 0)); // 增加宽度以为折叠控件留出空间
        setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
        setOpaque(true);
        setBackground(Color.LIGHT_GRAY);
        
        // 监听文本变化
        textComponent.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                scheduleRepaint();
            }
            
            @Override
            public void removeUpdate(DocumentEvent e) {
                scheduleRepaint();
            }
            
            @Override
            public void changedUpdate(DocumentEvent e) {
                scheduleRepaint();
            }
        });
        
        // 监听视图变化
        textComponent.addPropertyChangeListener("document", new PropertyChangeListener() {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                scheduleRepaint();
            }
        });
    }
    
    // 延迟重绘，避免频繁更新
    private void scheduleRepaint() {
        if (repaintTimer != null && repaintTimer.isRunning()) {
            repaintTimer.restart();
        } else {
            repaintTimer = new Timer(100, e -> {
                repaint();
                repaintTimer = null;
            });
            repaintTimer.setRepeats(false);
            repaintTimer.start();
        }
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        
        // 获取可见区域
        Rectangle clip = g.getClipBounds();
        g.setColor(getBackground());
        g.fillRect(clip.x, clip.y, clip.width, clip.height);
        
        // 设置字体和颜色
        g.setFont(textComponent.getFont());
        g.setColor(Color.BLACK);
        
        FontMetrics fontMetrics = g.getFontMetrics();
        int fontHeight = fontMetrics.getHeight();
        int ascent = fontMetrics.getAscent();
        
        // 计算第一行和最后一行
        int startOffset = textComponent.viewToModel(new Point(0, clip.y));
        int endOffset = textComponent.viewToModel(new Point(0, clip.y + clip.height));
        
        try {
            int startLine = getLineNumber(startOffset);
            int endLine = getLineNumber(endOffset);
            
            // 绘制行号（限制绘制的行数以提高性能）
            int maxLinesToDraw = 2000; // 限制最多绘制2000行
            int linesToDraw = Math.min(endLine - startLine + 1, maxLinesToDraw);
            
            for (int line = startLine; line <= startLine + linesToDraw && line <= endLine; line++) {
                String lineNumber = String.valueOf(line + 1);
                int y = getYPositionOfLine(line) + ascent;
                int x = getWidth() - fontMetrics.stringWidth(lineNumber) - 5;
                g.drawString(lineNumber, x, y);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private int getLineNumber(int offset) {
        Element root = textComponent.getDocument().getDefaultRootElement();
        return root.getElementIndex(offset);
    }
    
    private int getYPositionOfLine(int line) {
        Element root = textComponent.getDocument().getDefaultRootElement();
        if (line >= root.getElementCount()) {
            return 0;
        }
        
        try {
            Element element = root.getElement(line);
            Rectangle r = textComponent.modelToView(element.getStartOffset());
            return r.y;
        } catch (BadLocationException e) {
            return 0;
        }
    }
}